/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = db2_param.c                                                */
/*  NOTE      = TDS 请求解析                                                  */
/*  DATE      = 2015/03/19 by zhengxd                                         */
/******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#include "db2_core.h"
#include "db2_froca.h"
#include "db2_param.h"

/*******************************************************************************
*  FUNC     :  取得参数头部信息
*  ARGS     :  p_st_fragment(分片数据信息)
*           :  i_whole_flg(参数)
*           :  p_ui_ddm_left_len(DDM剩余长度)
*           :  p_i_param_cp(code point)
*           :  p_ui_param_bd_len(参数体长度)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*              APM_L7_ANALYZE_TODO  (more data)
*              APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     :
*******************************************************************************/
int db2_get_param_hd_info(L7_fragment_db2 *p_st_fragment
                         , int i_whole_flg
                         , unsigned int *p_ui_ddm_left_len
                         , int *p_i_param_cp
                         , unsigned int *p_ui_param_bd_len)
{
    int i_ret = FR_SUCC;
    uint16_t u16_cp = 0;
    uint16_t u16_len = 0;
    Frbyte_Packet *p_st_data = p_st_fragment->p_st_data;

    /* 之前已经取得参数code point */
    if (p_st_fragment->i_param_cp != DRDA_CP_NULL)
    {
        *p_i_param_cp = p_st_fragment->i_param_cp;
        *p_ui_param_bd_len = p_st_fragment->ui_param_len;
        return APM_L7_ANALYZE_SUCC;
    }
    /* 设置解析到参数的位置 */
    p_st_fragment->u64_parsed_index = bytebuff_getPosition(p_st_data);

    /* parameter至少有4位 */
    if (*p_ui_ddm_left_len < DRDA_PARAM_HD_LEN)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /* 实际取得的数据不足 */
    if (bytebuff_remaining(p_st_data) < DRDA_PARAM_HD_LEN)
    {
        if (i_whole_flg == DB2_TRUE)
        {
            return APM_L7_ANALYZE_FAIL;
        }
        else
        {
            return APM_L7_ANALYZE_TODO;
        }
    }

    /* 取得参数长度  */
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_len, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC || u16_len < DRDA_PARAM_HD_LEN)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /* 取得参数 CODE POINT */
    i_ret = bytebuff_get_short(p_st_data, 2, &u16_cp, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /* 设置出力 */
    *p_i_param_cp = u16_cp;
    p_st_fragment->i_param_cp = u16_cp;
    *p_ui_ddm_left_len -= DRDA_PARAM_HD_LEN;
    *p_ui_param_bd_len = u16_len - DRDA_PARAM_HD_LEN;
    p_st_fragment->ui_param_len = u16_len - DRDA_PARAM_HD_LEN;
    /* 设置解析到参数的位置 */
    p_st_fragment->u64_parsed_index = bytebuff_getPosition(p_st_data);
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  跳过parameter
*  ARGS     :  p_st_data(入力bytebuffer)
*           :  ui_param_len(parameter长度)
*           :  i_whole_flg(packet完整标识)
*           :  p_ui_ddm_left_len(DDM剩余长度)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*              APM_L7_ANALYZE_TODO  (more data)
*              APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     :
*******************************************************************************/
int db2_skip_param(Frbyte_Packet *p_st_data
                  , unsigned int ui_param_len
                  , int i_whole_flg
                  , unsigned int *p_ui_ddm_left_len)
{
    /* 实际本次DDM的遗留长度比parameter体部的长度还小 */
    if (*p_ui_ddm_left_len < ui_param_len)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /* 剩余长度不足 */
    if (ui_param_len > (unsigned int)bytebuff_remaining(p_st_data))
    {
        if (i_whole_flg == DB2_TRUE)
        {
            return APM_L7_ANALYZE_FAIL;
        }
        else
        {
            /* 设置要跳过的长度 */
            bytebuff_set_skip(p_st_data, ui_param_len - bytebuff_remaining(p_st_data));
            return APM_L7_ANALYZE_TODO;
        }
    }

    /* 跳过当前parameter */
    bytebuff_skip(p_st_data, ui_param_len);
    *p_ui_ddm_left_len -= ui_param_len;
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析MGRLVLLS取得CCSID
*  ARGS     :  p_st_data(入力bytebuffer)
*           :  ui_param_len(parameter长度)
*           :  i_whole_flg(packet完整标识)
*           :  p_ccsid(CCSID)
*           :  ui_ccsid_size(CCSID SIZE)
*           :  p_ui_ddm_left_len(DDM剩余长度)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*              APM_L7_ANALYZE_TODO  (more data)
*              APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     :
*******************************************************************************/
int db2_parse_mgrlvlls(Frbyte_Packet *p_st_data
                      , unsigned int ui_param_len
                      , int i_whole_flg
                      , char *p_ccsid
                      , unsigned int ui_ccsid_size
                      , unsigned int *p_ui_ddm_left_len)
{
    int i_ret = FR_SUCC;
    uint16_t u16_cp = 0;
    uint16_t u16_value = 0;
    int i_get_ccsid_flg = DB2_FALSE;
    int i_get_unicode_flg = DB2_FALSE;

    /* 实际本次DDM的遗留长度比parameter体部的长度还小 */
    if (*p_ui_ddm_left_len < ui_param_len)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /* 剩余长度不足 */
    if (ui_param_len > (unsigned int)bytebuff_remaining(p_st_data))
    {
        if (i_whole_flg == DB2_TRUE)
        {
            return APM_L7_ANALYZE_FAIL;
        }
        else
        {
            return APM_L7_ANALYZE_TODO;
        }
    }
    *p_ui_ddm_left_len -= ui_param_len;

    while (ui_param_len >= 4)
    {
        /* 取得参数 CODE POINT */
        i_ret = bytebuff_get_short(p_st_data, 2, &u16_cp, BYTE_BIG_ENDIAN);
        if (i_ret != FR_SUCC)
        {
            return APM_L7_ANALYZE_FAIL;
        }

        switch (u16_cp)
        {
            case DRDA_CP_CCSIDMGR:
                /* 根据协议CCSIDMGR和UNICODEMGR是互斥的 */
                if (i_get_unicode_flg == DB2_TRUE)
                {
                    return APM_L7_ANALYZE_FAIL;
                }

                /* 取得CCSIDMGR值 */
                i_ret = bytebuff_get_short(p_st_data, 2, &u16_value, BYTE_BIG_ENDIAN);
                if (i_ret != FR_SUCC)
                {
                    return APM_L7_ANALYZE_FAIL;
                }

                /* 1.
                * If the target server does not support the CCSIDMGR, the
                * mgrlvlls parameter returned for the EXCSAT command contains
                * the codepoint of the CCSIDMGR and the value zero (0) for the
                * level number. The source server must use CCSID 500 for the
                * DDM parameters containing character data.
                */

                /* 2.
                * When sent by the target server, 0xFFFF means the CCSID
                * the source server requested is not supported.
                */

                /* 当目标服务器不支持时，设置为默认的CCSID(500) */
                if (u16_value == 0 || u16_value == 0xFFFF)
                {
                    u16_value = 500;
                }
                break;

            case DRDA_CP_UNICODEMGR:
                /* 根据协议CCSIDMGR和UNICODEMGR是互斥的 */
                if (i_get_ccsid_flg == DB2_TRUE)
                {
                    return APM_L7_ANALYZE_FAIL;
                }
                /* 取得UNICODEMGR值 */
                i_ret = bytebuff_get_short(p_st_data, 2, &u16_value, BYTE_BIG_ENDIAN);
                if (i_ret != FR_SUCC || (u16_value != 1208 && u16_value != 0))
                {
                    return APM_L7_ANALYZE_FAIL;
                }

                break;

            case DRDA_CP_AGENT:
            case DRDA_CP_CMNAPPC:
            case DRDA_CP_CMNSYNCPT:
            case DRDA_CP_CMNTCPIP:
            case DRDA_CP_DICTIONARY:
            case DRDA_CP_RDB:
            case DRDA_CP_RSYNCMGR:
            case DRDA_CP_SECMGR:
            case DRDA_CP_SQLAM:
            case DRDA_CP_SUPERVISOR:
            case DRDA_CP_SYNCPTMGR:
            case DRDA_CP_XAMGR:
                bytebuff_skip(p_st_data, 2);
                break;

            default:
                return APM_L7_ANALYZE_FAIL;
        }
        ui_param_len -= 4;
    }

    /* 格式不正 */
    if (ui_param_len)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /* 设置CCSID */
    if (i_get_unicode_flg == DB2_TRUE)
    {
        snprintf(p_ccsid, ui_ccsid_size, "%s", "UTF-8");
    }
    else if (i_get_ccsid_flg == DB2_TRUE)
    {
        snprintf(p_ccsid, ui_ccsid_size, "CP%d", u16_value);
    }

    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析PKGNAMCSN取得session number
*  ARGS     :  p_st_data(入力bytebuffer)
*           :  ui_param_len(parameter长度)
*           :  i_whole_flg(packet完整标识)
*           :  p_ui_ddm_left_len(DDM剩余长度)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*              APM_L7_ANALYZE_TODO  (more data)
*              APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     :
*******************************************************************************/
int db2_get_sess_num(Frbyte_Packet *p_st_data
                    , unsigned int ui_param_len
                    , int i_whole_flg
                    , unsigned int *p_ui_ddm_left_len
                    , int64_t *p_i64_sess_num)
{
    int i_ret = APM_L7_ANALYZE_SUCC;

    /* 实际本次DDM的遗留长度比parameter体部的长度还小 */
    /* 根据协议PKGNAMCSN的最短长度是64 */
    if (*p_ui_ddm_left_len < ui_param_len
        || ui_param_len < 64)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /* 长度不够 */
    if (ui_param_len > (unsigned int)bytebuff_remaining(p_st_data))
    {
        if (i_whole_flg == DB2_TRUE)
        {
            return APM_L7_ANALYZE_FAIL;
        }
        else
        {
            return APM_L7_ANALYZE_TODO;
        }
    }

    /* 根据协议可知最后两位是存放session number的 */
    bytebuff_skip(p_st_data, ui_param_len - 2);
    *p_ui_ddm_left_len -= ui_param_len;
    ui_param_len = 2;
    /* 取得session number */
    i_ret = db2_get_bindr(p_st_data, 2, i_whole_flg
                         , p_i64_sess_num, &ui_param_len);
    return i_ret;
}

/*******************************************************************************
*  FUNC     :  取得SYNCTYPE
*  ARGS     :  p_st_data(入力bytebuffer)
*           :  ui_param_len(parameter长度)
*           :  i_whole_flg(packet完整标识)
*           :  p_u8_syntype(取得的值)
*           :  p_ui_ddm_left_len(DDM剩余长度)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*              APM_L7_ANALYZE_TODO  (more data)
*              APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     :
*******************************************************************************/
int db2_get_synctype(Frbyte_Packet *p_st_data
                     , unsigned int ui_param_len
                     , int i_whole_flg
                     , uint8_t *p_u8_syntype
                     , unsigned int *p_ui_ddm_left_len)
{
    /* 根据协议长度是1byte */
    if (ui_param_len != 1)
    {
        frdbg("SYNCTYPE parameter length is incorrect!\n");
        return APM_L7_ANALYZE_FAIL;
    }
    /* 剩余长度不足 */
    if (ui_param_len > (unsigned int)bytebuff_remaining(p_st_data))
    {
        if (i_whole_flg == DB2_TRUE)
        {
            return APM_L7_ANALYZE_FAIL;
        }
        else
        {
            return APM_L7_ANALYZE_TODO;
        }
    }

    /* 取得SYNCTYPE值 */
    bytebuff_get_char(p_st_data, p_u8_syntype);
    *p_ui_ddm_left_len -= ui_param_len;
    return APM_L7_ANALYZE_SUCC;
}
